﻿#include "MessageSerializer.h"
#include "ProcessManagerInterface.h"
#include "UI_Simulator.h"

using namespace ProcessManager;

BOOL CALLBACK lpEnumFunc(HWND vWindowHandle, LPARAM vLParam)
{
	FHWndsArg* pArg = (FHWndsArg*)vLParam;
	DWORD  ProcessID;
	GetWindowThreadProcessId(vWindowHandle, &ProcessID);
	if (ProcessID == pArg->dwProcessId)
	{
		pArg->vecHWnds->push_back(vWindowHandle);
	}
	return TRUE;
}

void getWindowHandleByProcessID(DWORD vProcessID, std::vector<HWND>& vWindowHandleSet)
{
	FHWndsArg wi;
	wi.dwProcessId = vProcessID;
	wi.vecHWnds = &vWindowHandleSet;
	EnumWindows(lpEnumFunc, (LPARAM)&wi);
}

void sendUIMessage(HWND hWnd, const SMessage& vMessage, double vActuralTimestamp)
{
	if (hWnd != NULL)
	{
		std::cout << "MessageId: " << vMessage._MessageID << " MessageType: " << vMessage._MessageStr << std::endl;
		switch (vMessage._Message)
		{
		case WM_LBUTTONDOWN:
		case WM_MBUTTONDOWN:
		case WM_RBUTTONDOWN:
		case WM_XBUTTONDOWN:
		case WM_LBUTTONDBLCLK:
		case WM_MBUTTONDBLCLK:
		case WM_RBUTTONDBLCLK:
		case WM_XBUTTONDBLCLK:
		case WM_XBUTTONUP:
		case WM_LBUTTONUP:
		case WM_MBUTTONUP:
		case WM_RBUTTONUP:
		{
			POINT CursorPoint;
			CursorPoint.x = GET_X_LPARAM(vMessage._LParam);
			CursorPoint.y = GET_Y_LPARAM(vMessage._LParam);
			ScreenToClient(hWnd, &CursorPoint);
			LPARAM newLParam = MAKELPARAM(CursorPoint.x, CursorPoint.y);
			PostMessage(hWnd, vMessage._Message, vMessage._WParam, newLParam);
			break;
		}
		case WM_INPUT:
		{
			LPARAM newLParam = MAKELPARAM(vMessage._XPosRelative, vMessage._YPosRelative);
			PostMessage(hWnd, WM_INPUT, vMessage._WParam, newLParam);
			break;
		}
		case WM_MOUSEMOVE:
			SetCursorPos(vMessage._XPosRelative, vMessage._YPosRelative);
			break;
		case WM_DESTROY:
		case WM_CHAR:
			break;
		default:
			PostMessage(hWnd, vMessage._Message, vMessage._WParam, vMessage._LParam);
			break;
		}
	}
};

int main(int argc, char* argv[])
{
	std::string ReceiverName = argc == 1 ? "UnrealEditor.exe" : "CppProject.exe";
	DWORD ProcessID = CProcessManagerInterface::getProcessIDByName(ReceiverName);
	HWND hMainWnd = NULL;

	if (ProcessID != (DWORD)INVALID_HANDLE_VALUE)
	{
		std::vector<HWND> WindowHandleSet;
		getWindowHandleByProcessID(ProcessID, WindowHandleSet);
		for (const HWND& h : WindowHandleSet)
		{
			HWND Parent = GetParent(h);
			if (Parent == NULL)
			{
				hMainWnd = h;
				break;
			}
		}
	}

	if (hMainWnd != NULL)
	{
		PostMessage(hMainWnd, WM_USER + 1, NULL, NULL);//告诉游戏进程在回放消息，无需记录
		SetForegroundWindow(hMainWnd);
		SetFocus(hMainWnd);
		CMessageSerializer* pSerializer = nullptr;
		if (argc == 1)
		{
			OPENFILENAME ofn = { 0 };
			TCHAR szBuffer[MAX_PATH] = { 0 };
			ofn.lStructSize = sizeof(ofn);
			ofn.hwndOwner = NULL;
			ofn.lpstrFilter = _T("Binary Files(*.bin)\0 * .bin\0");
			ofn.lpstrInitialDir = _T("D:\\");
			ofn.lpstrFile = szBuffer;
			ofn.nMaxFile = sizeof(szBuffer) / sizeof(*szBuffer);
			ofn.Flags = OFN_FILEMUSTEXIST;
			BOOL bSel = GetOpenFileName(&ofn);
			if (bSel)
			{
				int size = WideCharToMultiByte(CP_UTF8, 0, szBuffer, -1, NULL, 0, NULL, NULL);
				char* charString = new char[size];
				WideCharToMultiByte(CP_UTF8, 0, szBuffer, -1, charString, size, NULL, NULL);
				pSerializer = new CMessageSerializer(charString);
			}
		}
		else
		{
			pSerializer = new CMessageSerializer(argv[1]);
		}

		std::this_thread::sleep_for(std::chrono::seconds(2));

		std::vector<SMessage> Messages;
		pSerializer->load(Messages);
        _ASSERTE(!Messages.empty());

		std::cout << "准备发送 " << Messages.size() << " 条消息" << std::endl;

		double LastTimestamp = -1;
		double TimeElapsed = 0;
		std::chrono::time_point<std::chrono::steady_clock> StartTimePoint = std::chrono::high_resolution_clock::now();

		for (auto& Message : Messages)
		{
			_ASSERTE((Message._Timestamp >= 0) && (Message._Timestamp >= LastTimestamp));
			LastTimestamp = Message._Timestamp;

			std::chrono::duration<double> Duration = std::chrono::high_resolution_clock::now() - StartTimePoint;
			TimeElapsed = Duration.count() * 1000.0;
			while (TimeElapsed < Message._Timestamp)
			{
				Duration = std::chrono::high_resolution_clock::now() - StartTimePoint;
				TimeElapsed = Duration.count() * 1000.0;
			}
			sendUIMessage(hMainWnd, Message, TimeElapsed);
		}
	}
	return 0;
}